package com.itheima.service.impl;

import cn.afterturn.easypoi.entity.ImageEntity;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.word.WordExportUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.mapper.UserMapper;
import com.itheima.pojo.Resource;
import com.itheima.pojo.User;
import com.itheima.service.IResourceService;
import com.itheima.service.IUserService;
import com.itheima.utils.EntityUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.Units;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.web.multipart.MultipartFile;


import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements IUserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private IResourceService resourceService;


    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");

    public List<User> findAll() {
        return userMapper.selectList(null);
    }

    public List<User> findPage(Integer page, Integer pageSize) {
        Page<User> userPage1 = new Page<>(page, pageSize);
        Page<User> userPage = userMapper.selectPage(userPage1, null);
        return userPage.getRecords();
    }

    /**
     * 导出JSL文件
     * @param response
     */
//    public void downLoadXlsByJxl(HttpServletResponse response) throws IOException, WriteException {
//        // 获取输出流
//        OutputStream outputStream = response.getOutputStream();
//        // 获取workbook对象（一个workbook就相当于一个Excel文件）
//        WritableWorkbook workbook = Workbook.createWorkbook(outputStream);
//        // 获取sheet对象（一个对象就相当于一个页面）
//        // 参数一：当前sheet的名称   参数二：当前页面的索引值，即：第几页
//        WritableSheet sheet = workbook.createSheet("一个JXL入门", 0);
//        // 根据实际需求，调整表格中单元格的宽度
//        // 参数一：列的索引值（从0开始）  参数二：当前单元格要设置的宽度
//        sheet.setColumnView(0,5); // 实测5个单位的宽度可以放下4位数左右
//        sheet.setColumnView(1,8);
//        sheet.setColumnView(2,15);
//        sheet.setColumnView(3,15);
//        sheet.setColumnView(4,30);
//        // 处理表头，Label表示一个单元格
//        // 参数1：当前单元格的列索引（索引从0开始）
//        // 参数2：当前单元格的行索引（索引从0开始）
//        // 参数3：当前单元格的内容
//        String[] headerArr = new String[]{"编号","姓名","手机号","入职日期","当前住址"};
//        Label label = null;
//        for (int i = 0; i < headerArr.length; i++) {
//            label = new Label(i,0,headerArr[i]);
//            // 将头行的每一个单元格添加到sheet中
//            sheet.addCell(label);
//        }
//        // 此时表头已经处理完成了
//        List<User> userList = findAll();
//        // 创建行-> 每个单元格对象就是Label
//        int rowIndex = 1;
//        for (int i = 0; i < userList.size(); i++) {
//            User user = userList.get(i);
//            // 编号，姓名，手机号，入职日期，当前住址
//            // 每添加一个单元格，就将数据添加到sheet对象中
//            label = new Label(0,rowIndex,rowIndex+"");
//            sheet.addCell(label);
//            label = new Label(1,rowIndex,user.getUserName());
//            sheet.addCell(label);
//            label = new Label(2,rowIndex,user.getPhone());
//            sheet.addCell(label);
//            label = new Label(3,rowIndex,simpleDateFormat.format(user.getHireDate()));
//            sheet.addCell(label);
//            label = new Label(4,rowIndex,user.getAddress());
//            sheet.addCell(label);
//            rowIndex++;
//        }
//        // 数据处理完毕，执行导出即可
//        // 文件的导出重点是：一个流两个头
//        // 一个流：即一个输出流
//        // 两个头：文件的打开方式：in-line和attachment，前者是在浏览器中打开，后者是以附件的形式将文件下载下来
//        String fileName = "JXL测试文件.xls";
//        // 重点：由于浏览器对中文的支持不友好，所以文件名若为中文，尽量通过中文获取字节，再转ISO8859-1
//        response.setHeader("content-disposition","attachment;filename="+new String(fileName.getBytes(),"ISO8859-1"));
//        // 导出时的格式是：application/vnd。ms-excel
//        response.setContentType("application/vnd.ms-excel");
//        workbook.write();
//        workbook.close();
//        outputStream.close();
//    }

    /**
     * 使用poi导出带样式的文件（首行合并单元格并居中，第二行为表头信息，从第三行开始为相关数据）
     * @param response
     */
    @Override
    public void downLoadXlsxByPoi(HttpServletResponse response) throws IOException {
        // 准备表头数据
        String[] titleArr = new String[]{"编号","姓名","手机号","入职日期","现住址"};
        int length = titleArr.length;
        // workbook相当于一个Excel文件
        Workbook workbook = new XSSFWorkbook();
        // 在文件中创建一个工作簿
        Sheet sheet = workbook.createSheet();
        // 设置首行的单元格式
        CellStyle firstCellStyle = workbook.createCellStyle();
        // 设置边框
        firstCellStyle.setBorderTop(BorderStyle.THIN);    // 顶部线条
        firstCellStyle.setBorderBottom(BorderStyle.THIN); // 底部线条
        firstCellStyle.setBorderLeft(BorderStyle.THIN);   // 左边线条
        firstCellStyle.setBorderRight(BorderStyle.THIN);  // 右边线条
        // 水平方向居中
        firstCellStyle.setAlignment(HorizontalAlignment.CENTER);
        // 垂直方向居中
        firstCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        // 注意：合并单元格时，针对的对象是页面（sheet）因为可能不仅左右合并，上下也需合并
        // 设置首行的单元格风格（合并单元格：参数依次是：开始行，截止行，开始列，截止列）
        CellRangeAddress cellAddresses = new CellRangeAddress(0,0,0,length-1);
        sheet.addMergedRegion(cellAddresses);
        // 创建字体对象（首行为黑体18加粗）
        Font firstFont = workbook.createFont();
        firstFont.setFontName("黑体");
        firstFont.setFontHeightInPoints((short) 18);
        firstFont.setBold(true);
        firstCellStyle.setFont(firstFont);
        // 完成首行的格式编写
        // 通过工作簿创建行对象（首行合并单元格并居中）
        Row firstRow = sheet.createRow(0);
        firstRow.setHeightInPoints((short) 43); // 设置行高
        Cell firstCell = firstRow.createCell(0);
        firstCell.setCellValue("用户信息表");
        firstCell.setCellStyle(firstCellStyle);

        // 处理（第二行）表头数据
        // 同样通过文件对象，创建一份单元格样式
        CellStyle titleCellStyle = workbook.createCellStyle();
        titleCellStyle.cloneStyleFrom(firstCellStyle);
        // 改字体为宋体14
        Font titleFont = workbook.createFont();
        titleFont.setFontName("宋体");
        titleFont.setFontHeightInPoints((short) 12);
        titleFont.setBold(true);
        titleCellStyle.setFont(titleFont);
        Row titleRow = sheet.createRow(1);
        for (int i = 0; i < length; i++) {
            Cell cell = titleRow.createCell(i);
            cell.setCellValue(titleArr[i]);
            // 设置单元格样式
            cell.setCellStyle(titleCellStyle);
        }

        // 主体数据
        // 同样要设置内容的单元格风格
        CellStyle contentCellStyle = workbook.createCellStyle();
        contentCellStyle.cloneStyleFrom(titleCellStyle);
        Font contentFont = workbook.createFont();
        contentFont.setFontName("宋体");
        contentFont.setFontHeightInPoints((short) 10);
        contentFont.setBold(false);
        contentCellStyle.setFont(contentFont);
        List<User> userList = list();
        int startRow = 2;
        for (int i = 0; i < userList.size(); i++) {
            User user = userList.get(i);
            Row row = sheet.createRow(startRow);
            Cell cell0 = row.createCell(0);
            Cell cell1 = row.createCell(1);
            Cell cell2 = row.createCell(2);
            Cell cell3 = row.createCell(3);
            Cell cell4 = row.createCell(4);
            cell0.setCellValue(user.getId());
            cell1.setCellValue(user.getUserName());
            cell2.setCellValue(user.getPhone());
            cell3.setCellValue(simpleDateFormat.format(user.getHireDate()));
            cell4.setCellValue(user.getAddress());
            // 设置单元格样式
            cell0.setCellStyle(titleCellStyle);
            cell1.setCellStyle(titleCellStyle);
            cell2.setCellStyle(titleCellStyle);
            cell3.setCellStyle(titleCellStyle);
            cell4.setCellStyle(titleCellStyle);
            startRow++;
        }

                // 数据处理完毕，执行导出即可
        // 文件的导出重点是：一个流两个头
        // 一个流：即一个输出流
        // 两个头：文件的打开方式：in-line和attachment，前者是在浏览器中打开，后者是以附件的形式将文件下载下来
        String fileName = "POI测试文件.xlsx";
        // 重点：由于浏览器对中文的支持不友好，所以文件名若为中文，尽量通过中文获取字节，再转ISO8859-1
        response.setHeader("content-disposition","attachment;filename="+new String(fileName.getBytes(),"ISO8859-1"));
        // 导出时的格式是：application/vnd。ms-excel
        response.setContentType("application/vnd.ms-excel");
        workbook.write(response.getOutputStream());
        workbook.close();
    }

    /**
     * 根据员工id，导出对应的员工详情
     * @param id    员工主键id
     * @param request 请求
     * @param response 响应
     */
    @Override
    public void downLoadUserInfoWithTemplate(Long id, HttpServletRequest request, HttpServletResponse response) throws IOException, InvalidFormatException {
        if (null==id || id<1) {
            throw new RuntimeException("参数异常，导出失败");
        }
        User user = getById(id);
        // 获取导出的模板对象
        // 先获取到根目录，再通过根目录获取到模板对象
        File rootPath = new File(ResourceUtils.getURL("classpath:").getPath());
        File template = new File(rootPath.getAbsolutePath(), "/excel_template/userInfo.xlsx");

        // 通过模板创建workbook对象
        Workbook workbook = new XSSFWorkbook(template);
        // 获取到第一页表格对象，进而获取到单元格，最后进行数据映射即可
        Sheet sheet = workbook.getSheetAt(0);
        // 用户名
        Cell nameCell = sheet.getRow(1).getCell(1);
        nameCell.setCellValue(user.getUserName());
        // 头像 a.通过文件所在位置获取到file对象
        File templateFile = new File(rootPath, user.getPhoto());
        // b.通过IOUtil工具类将该模板信息写入到
        BufferedImage bufferedImage = ImageIO.read(templateFile);
        // 创建字节输出流
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        // 通过ImageIO工具类进行写出（该步骤完成图片信息的创建）
        ImageIO.write(bufferedImage,"jpg",byteArrayOutputStream);
        // POI主要提供了两个类来处理照片，这两个类是Patriarch和ClientAnchor
        // Patriarch负责在表中创建图片；ClientAnchor负责设置图片的大小位置。
        Drawing<?> patriarch = sheet.createDrawingPatriarch();
        // 注意：八个参数两两一组，每组依次表示：图片左上角偏移量、右下角偏移量、左上角所在的列和行的索引值、图片右下角所在的列和行的索引值（但此处以行和列的交叉的左上角处为准，因此col2和row2的值需要+1）
        ClientAnchor clientAnchor = new XSSFClientAnchor(9000,9000,-9000,-9000,2,1,4,5);
        // 设置图片位置
        patriarch.createPicture(clientAnchor,workbook.addPicture(byteArrayOutputStream.toByteArray(),Workbook.PICTURE_TYPE_JPEG));
//        dealAvatar();
        // 手机号
        Cell phoneCell = sheet.getRow(2).getCell(1);
        phoneCell.setCellValue(user.getPhone());
        // 生日
        Cell birthdayCell = sheet.getRow(3).getCell(1);
        birthdayCell.setCellValue(user.getBirthday());
        // 工资
        Cell salaryCell = sheet.getRow(4).getCell(1);
        salaryCell.setCellValue(user.getSalary());
        // 入职日期
        Cell joinCell = sheet.getRow(5).getCell(1);
        joinCell.setCellValue(simpleDateFormat.format(user.getHireDate()));

        // 省份
        Cell provCell = sheet.getRow(6).getCell(1);
        provCell.setCellValue(user.getProvince());
        // 城市
        Cell cityCell = sheet.getRow(6).getCell(3);
        cityCell.setCellValue(user.getCity());
        // 当前住址
        Cell addressCell = sheet.getRow(7).getCell(1);
        addressCell.setCellValue(user.getAddress());

        // 执行导出操作
        String filename="用户详细信息数据.xlsx";
        // 设置文件的打开方式和mime类型
        ServletOutputStream outputStream = response.getOutputStream();
        // 设置请求头的配置：attachment表示以附件的形式打开（即下载到本地，而并非在网页中打开）
        // 若文件名包含中文，最好通过字节的形式进行new String（编码形式设置为ISO8859-1），否则容易乱码
        response.setHeader("Content-Disposition","attachment;filename="+new String(filename.getBytes(),"ISO8859-1"));
        // 设置响应类型
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        workbook.write(outputStream);
    }
    /**
     * 下载员工合同
     * @param id 员工id
     * @param response 用于导出文件时的响应对象
     */
    @Override
    public void downLoadContract(Long id, HttpServletResponse response) throws Exception {
        // 获取合同模板根路径（即：resources的路径）
        String rootPath = ResourceUtils.getURL("classpath:").getPath();
        File template = new File(rootPath,"/word_template/contract_template.docx");
        // 根据模板创建word文件对象
        XWPFDocument document = new XWPFDocument(new FileInputStream(template));

        // 查询到对应的员工信息，并将其转为map格式方便替换
        User user = getById(id);
        String userName = user.getUserName();
        Map<String,String> paramMap = new HashMap<>();
        paramMap.put("userName", userName);
        paramMap.put("hireDate",simpleDateFormat.format(user.getHireDate()));
        paramMap.put("address",user.getAddress());
        Set<String> keySet = paramMap.keySet();
        // 替换操作（正文和表格）
        // 替换正文
        List<XWPFParagraph> paragraphs = document.getParagraphs();
        for (XWPFParagraph paragraph : paragraphs) {
            List<XWPFRun> runs = paragraph.getRuns();
            for (XWPFRun run : runs) {
                String text = run.getText(0);
                for (String key : keySet) {
                    if (text.contains(key)) {
                        run.setText(text.replaceAll(key,paramMap.get(key)),0);
                    }
                }
            }
        }
        // 获取到当前员工的相关物品信息
        List<Resource> resourceList = resourceService.lambdaQuery()
                .eq(Resource::getUserId, id)
                .list();
        // 替换表格
        XWPFTable xwpfTable = document.getTables().get(0);  // 获取到表格对象（获取整个word文件中的所有表格，本例中只有一个表格，故可以直接get(0)）
        // 需要进行添加行操作，resourceList的size是多少此时就添加多少行
        XWPFTableRow tableRow = xwpfTable.getRow(0);
        int rowIndex = 1;
        for (Resource resource : resourceList) {
            // 需要对行对象进行深复制（默认是浅复制）
            cloneRow(xwpfTable, tableRow, rowIndex);
            // 获取表格中各行的数据，rowIndex从1开始，跳过标题行
            XWPFTableRow curRow = xwpfTable.getRow(rowIndex);
            // 分别获取当前行的第一、第二、第三、第四个单元格并为其赋上相应的值
            curRow.getCell(0).setText(resource.getName());  // 名称
            curRow.getCell(1).setText(resource.getPrice().toString());  // 价值
            curRow.getCell(2).setText(resource.getNeedReturn()?"需要":"不需要");  // 是否需要归还
            // resource.getPhoto()获取到的是相对路径下的地址，需要通过拼接rootPath从而获取到图片对象
            File photo = new File(rootPath, "/static" + resource.getPhoto());
            setCellImage(curRow.getCell(3),photo);
            rowIndex++;
        }

        // 导出操作
        String fileName = "员工（"+userName+"）合同.docx";
        // 设置响应头、相应格式
        response.setHeader("content-disposition","attachment;filename="+new String(fileName.getBytes(),"ISO8859-1"));
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        document.write(response.getOutputStream());
    }

    /**
     * 使用EasyPOI的方式进行用户信息导出
     * @param response
     */
    @Override
    public void downLoadWithEasyPOI(HttpServletResponse response) throws IOException {
        List<User> userList = list();
        // 重点是第三个参数，默认情况是导出HSSF类型的表格，即低版本；若需要导高版本的则需要设置以为XSSF
        // 参数一：小标题（首行上面的内容）   参数二：当前sheet页面的名称   参数三：导出表格的类型（HSSF低版本xls，不常用；XSSF高版本常用xlsx）
        ExportParams params = new ExportParams("使用EasyPOI实现导出","第一页", ExcelType.XSSF);
        Workbook workbook = ExcelExportUtil.exportExcel(params, User.class, userList);
        String fileName = "员工信息表-EasyPOI版.xlsx";
        response.setHeader("content-disposition","attachment;filename="+new String(fileName.getBytes(),"ISO8859-1"));
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        workbook.write(response.getOutputStream());
    }

    /**
     * 使用EasyPOI实现表格数据的导入
     * @param file 要导入的表格文件
     */
    @Override
    public void uploadExcelWithEasyPOI(MultipartFile file) throws Exception {
        // 需要在ImportParams中设置表格中是否有大表头以及所占的行数；是否有列名，以及列名占的行数
        ImportParams importParams = new ImportParams();
        importParams.setTitleRows(1);   // 大表头所占的行数
        importParams.setHeadRows(1);    // 列名所占的行数
        List<User> userList = ExcelImportUtil.importExcel(file.getInputStream(), User.class, importParams);
        if (!CollectionUtils.isEmpty(userList)) {
            for (User user : userList) {
                user.setId(null);
            }
            // 批量保存
            saveBatch(userList);
            log.info("成功导入：{}条用户信息",userList.size());
        }else {
            log.warn("没有可以导入的用户信息");
        }
    }

    /**
     * 使用EasyPOI实现带模板的表格导出
     * @param id 员工id
     * @param request 请求
     * @param response 响应
     */
    @Override
    public void downLoadUserInfoWithTemplateForEasyPoi(Long id, HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (null==id || id<1) {
            log.warn("员工id为空，或异常");
            return;
        }
        User user = getById(id);
        // 获取模板对象
        // 1、获取文件根目录
        String rootPath = ResourceUtils.getURL("classPath:").getPath();
        // 2、获取模板对象
        File template = new File(rootPath, "excel_template/userInfo_easyPoi.xlsx");
        // 3、设置目标参数，依次：模板路径、是否扫描所有页、自定义页名
        TemplateExportParams templateExportParams = new TemplateExportParams(template.getPath(), true, null);

        // 把user对象转为map
        Map<String, Object> userMap = EntityUtils.entityToMap(user);
        // 重点：对于图片的处理，需要将其封装在一个ImageEntity对象中
        ImageEntity imageEntity = new ImageEntity();
        imageEntity.setUrl(user.getPhoto());
        imageEntity.setColspan(2); // 所占列数
        imageEntity.setRowspan(4); // 所占行数
        userMap.put("photo",imageEntity);
        Workbook workbook = ExcelExportUtil.exportExcel(templateExportParams, userMap);

        String fileName = user.getUserName()+"信息.xlsx";
        // 设置响应头、相应格式
        response.setHeader("content-disposition","attachment;filename="+new String(fileName.getBytes(),"ISO8859-1"));
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        workbook.write(response.getOutputStream());

    }

    /**
     * 使用EasyPOI实现对word文档的导出
     * 注意：EasyPOI对word支持不太好，若文件中存在表格，则只能导出位于正文中的图片；如若是表格中的图片则无法导出，只能使用POI来实现
     * @param id 员工id
     * @param response
     */
    @Override
    public void downLoadContractByEasyPOI(Long id, HttpServletResponse response) throws Exception{
        // 获取根目录
        String rootPath = ResourceUtils.getURL("classPath:").getPath();
        // 根据根目录获取模板文件
        File template = new File(rootPath, "word_template/contract_template_easyPoi.docx");

        // 获取需要导出的对象信息
        User user = getById(id);
        String userName = user.getUserName();
        log.info("正在使用EasyPOI方式导出：{}的合同文档",userName);
        Map<String, Object> params = new HashMap<>();
        params.put("userName", userName);
        params.put("hireDate",simpleDateFormat.format(user.getHireDate()));
        params.put("address",user.getAddress());

        // 需要将办公用品数据封装到map中
        List<Map<String,Object>> mapList = new ArrayList<>();

        List<Resource> resourceList = resourceService.lambdaQuery().eq(Resource::getUserId,user.getId()).list();
        if (!CollectionUtils.isEmpty(resourceList)) {
            Map<String, Object> map = null;
            for (Resource resource : resourceList) {
                map = new HashMap<>();
                map.put("name",resource.getName());
                map.put("price",resource.getPrice());
                map.put("needReturn",resource.getNeedReturn());
                mapList.add(map);
            }
            params.put("maplist",mapList);
        }else {
            log.warn("用户{}没有相关的办公用品",userName);
        }

        // 执行导出
        String fileName = userName +"合同.docx";
        XWPFDocument document = WordExportUtil.exportWord07(template.getPath(), params);
        response.setHeader("content-disposition","attachment;filename="+new String(fileName.getBytes(),"ISO8859-1"));
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        document.write(response.getOutputStream());
        document.close();
    }

    /**
     * 设置表格中的图片
     * @param cell 当前的单元格（渲染图片的单元格）
     * @param photo 图片对象
     */
    private void setCellImage(XWPFTableCell cell, File photo) {
        // 获取该单元格中的所有内容
        List<XWPFParagraph> paragraphList = cell.getParagraphs();
        // 因为只是一个单元格且仅有一张图片，直接get(0)即可，并创建文本对象run
        XWPFRun newRun = paragraphList.get(0).createRun();
        // 为run添加图片（需要使用输入流）
        try (FileInputStream fileInputStream = new FileInputStream(photo);){
            newRun.addPicture(
                    fileInputStream,
                    XWPFDocument.PICTURE_TYPE_JPEG, // 图片类型
                    photo.getName(),    // 图片名称
                    Units.toEMU(100), // 需要使用poi提供的单位转换否则太小了看不清
                    Units.toEMU(50)); // 需要使用poi提供的单位转换否则太小了看不清
        } catch (Exception e) {
            throw new RuntimeException(e);
        }


    }

    /**
     * 深克隆行对象
     * @param xwpfTable 表格对象
     * @param sourceRow 行对象（数据源，即被复制的对象）
     * @param rowIndex  当前克隆的行数
     */
    private void cloneRow(XWPFTable xwpfTable, XWPFTableRow sourceRow, int rowIndex) {
        // 逻辑：创建一个全新的row对象，将模板对象的属性赋值给新行对象即可
        XWPFTableRow newRow = xwpfTable.insertNewTableRow(rowIndex);// 表示在rowIndex处创建一个全新的行对象
        newRow.getCtRow().setTrPr(sourceRow.getCtRow().getTrPr());  // 将源行对象的属性赋值给新行对象
        // 获取原行对象的单元格，若不为空则将原行对象中所有的单元格属性赋值给新建的单元格对象
        List<XWPFTableCell> tableCells = sourceRow.getTableCells();
        if (CollectionUtils.isEmpty(tableCells)) {
            // 说明表格是空的，直接返回即可
            return;
        }
        XWPFTableCell newCell = null;
        // 执行赋值单元格属性操作
        for (XWPFTableCell curCell : tableCells) {
            newCell = newRow.addNewTableCell();
            newCell.getCTTc().setTcPr(curCell.getCTTc().getTcPr());
            newCell.getParagraphs().get(0).getCTP().setPPr(curCell.getParagraphs().get(0).getCTP().getPPr());
        }
    }

}
